﻿#ifndef XQLOG_H
#define XQLOG_H
#include"XQHead.h"
#include"XQThreadQueue.hpp"
#include"XQLogInfo.h"
#include<QReadWriteLock>
#include<QWaitCondition>
#include<QHash>
#include<QObject>
#include<QJsonObject>
//日志
class XQLog :public QObject
{
	Q_OBJECT
public:
	enum ShowMode
	{
		cmd_out = 1,//CMD输出
		cmd_cpp = 2,//C++版cmd
		cmd_qt = 4,//Qt版cmd
		cmd_queue = 8,//cmd在队列线程运行
		local_out = 16,//本地文件输出
		local_queue = 32,//保存文件在队列线程运行
		showKey = 64,//显示日志key(名字)
		showLogType = 128,//显示日志类型
		showTime = 256,//显示时间
		dataLineFeed = 512//数据换行
	};
	friend void LogDefaultCMDOut(XQLog* log);
	friend void LogDefaultLocalOut(XQLog* log);
	friend void LogLocalOut(const XQLogOut& data);
	static QString variant_to_string(const QVariant& data);//格式转化
	static QJsonObject variant_to_json(const QVariant& data);//格式转化
	static QVariant json_to_variant(const QJsonObject& json);//格式转化
	XQLog(const QString& key);
	~XQLog();
	//创建一个新的单例
	static XQLog* Create(const QString& key, int flags= XQLog::cmd_out | XQLog::cmd_cpp | XQLog::showLogType);
	static XQLog* Create(const QString& key, LogType logType, int flags = XQLog::cmd_out | XQLog::cmd_cpp | XQLog::showLogType);
	//返回单例的指针
	static XQLog* Global(const QString& key);
	//返回是否是默认的单例
	static bool isDefaultGlobal(const QString& key);
	//删除单例
	static void remove(const QString& key);
	//日志类型转字符串输出
	static QString logType_toString(LogType logType);
	//任务线程是否在休眠
	static bool isTaskSleep();
	//等待线程休眠
	static void wait_task();
	//从本地读取
	static XQLogLocalDateList read_local(const QString& path);
public:
	//获得对应的单例
	XQLog* Global();
	QString key()const;
	bool isEmpty()const;
	qint64 size()const;
	XQLogSettings settings();
	//获得文本
	QString data_toString();
	//从本地读取
	XQLogLocalDateList read_local();
	//获得数据
	const QVariantList& data()const;
public:
	int logShowFlags();
	bool logShowFlags(int flags);
	bool logShowFlag(ShowMode mode);
	LogType logType();
	LogSaveType saveLocalType();
	QString localPath();
	QString timeFormat();
public:
	//设置日志的键值(名字)
	void setKey(const QString&key);
	void setLogShowFlags(int flags);
	void setLogShowFlag(ShowMode mode,bool on=true);
	void setLogType(LogType type);
	void saveLocalType(LogSaveType type);
	void setLocalPath(const QString& path);
	void setTimeFormat(const QString& format);
	//设置日志输出方式
	void setLogOutFunc_CMD(std::function<void(XQLog*)> outFunc= LogDefaultCMDOut);
	void setLogOutFunc_Local(std::function<void(XQLog*)> outFunc = LogDefaultLocalOut);
	void clear_local_file();
public:
	template<typename ...Args>
	void push_back(Args&&...args);
	void push_back(QVariantList& list);
	void push_back(QVariantList&& list);
	void push_back(const QVariantList& list);
	void push_back(const XQLogLocalDateList& list);
	void push_back(XQLogLocalDateList& list);
	void push_back(XQLogLocalDateList&& list);
	template<typename T>
	XQLog& operator<<(T&& data);
	template<typename T>
	XQLog& operator<<(T* ptr);
	XQLog& operator<<(QVariantList& list);
	XQLog& operator<<(QVariantList&& list);
	XQLog& operator<<(const QVariantList& list);
	XQLog& operator<<(XQLogDate&& data);
	XQLog& operator<<(XQLogDate& data);
	XQLog& operator<<(const XQLogDate& data);
	XQLog& operator<<(XQLogLocalDateList&& list);
	XQLog& operator<<(XQLogLocalDateList& list);
	XQLog& operator<<(const XQLogLocalDateList& list);
	QVariant& operator[](int nSel);
signals://信号
	void LogOut(const XQLogDate& data);
protected:
	//创建对应的单例用作信号和槽连接
	XQLog(const QString& key, bool isGlobal);
	void out();//输出
	void init();
	void Push_Back(const XQLogLocalDateList& list);
	void Push_Back(const XQLogDate& data);
protected:
	static XQThreadQueue<XQLogOut> m_queue;//日志输出队列
	static QThread* m_task;//任务
	static std::atomic<bool> m_taskSleep;//任务休眠
	static QWaitCondition m_wait;//条件变量
	static QReadWriteLock m_taskLock;//任务读写锁
	static QReadWriteLock m_lock;//共享读写锁
	static QHash<QString, XQLogSettings> m_Settings;//
	QString m_key;
	QVariantList m_data;//数据
};
template<typename T>
inline XQLog& XQLog::operator<<(T&& data)
{
	m_data << data;
	return *this;
}
template<typename T>
inline XQLog& XQLog::operator<<(T* ptr)
{
	auto text = QDebug::toString(ptr);
	push_back(std::move(text));
	return *this;
}
template<typename ...Args>
inline void XQLog::push_back(Args && ...args)
{
	QVariantList list{ std::forward<Args>(args)... };
	m_data.append(std::move(list));
}



#endif


